/*
 * @Author: qiulin_JXGM ql1746365080@gmail.com
 * @Date: 2024-09-19 10:21:28
 * @LastEditors: qiulin_JXGM ql1746365080@gmail.com
 * @LastEditTime: 2024-09-19 16:53:29
 * @FilePath: \SGFEM\DataStructure\FEM\Dynamic\include\EIGRLData.h
 */

/*
remarks： nastran帮助文档的内容，某些内容与我们计算方案不一致，为工参考并未删减。
1：SID必须被Case Control中的METHOD使用
2：V1 和 V2
的在振动分析中单位是HZ，在屈曲分析中是特征值。每个特征值是一个系数（factor），应力的预屈曲状态乘以该系数能得到由相应的特征向量定义的屈曲形状
3：屈曲分析中只支持位移归一化，质量归一被忽略。
4：根（特征值）按数值大小递增的顺序被找到。，首先找到接近于0的根，根的数值和类型参见下表
        V1      |    V2     |  ND      |   Number and Type of Roots Found
    ——————————————————————————————————————————————————————————————————————————————————————————
        V1      |    V2     |  ND      |   Lowest ND or all in range, whichever is smaller.
        V1      |    V2     |  blank   |   All in range
        V1      |    blank  |  ND      |   Lowest ND in range [V1,+∞]
        V1      |    blank  |  blank   |   Lowest root in range [V1,+∞]
        blank   |    blank  |  ND      |   Lowest ND roots in [-∞,+∞]
        blank   |    blank  |  blank   |   Lowest root. See Remark  11.
        blank   |    V2     |  ND      |   Lowest ND roots below V2
        blank   |    V2     |  blank   |   All below V2
5： 在振动分析中，如果V1<0.0,负特征值范围将被搜索（特征值与Vi的平方成正比，因此特征值的符号会被丢失），这也是一种诊断不可能模态的方法。
    在特征值分析中，V1与V2的负号没有这种特殊的逻辑。
6：特征值的是输出根据其数值排序，一个特征向量对应于一个特征值
7：MSGLVL 控制在特征值提取过程中诊断输出的数量。默认值为 0，表示抑制所有诊断输出。存在值时，会打印每次移位（at
    each shift）时接受的特征值。更高的值会导致更多级别的诊断输出。
8：MAXSET 用于限制最大块大小。未设置时，它由区域大小或 ND 设置，最大大小为 15。如果可用内存不足，它也可能会被重置。推荐使用默认值。
9：在振动分析中，如果 V1 为空，则计算所有小于零的根。小的负根通常是计算上的零值，表示刚体模态。
    有限的负根则表示模型存在问题。如果 V1 设置为零，则不计算负的特征值。
10：指定 SHFSCL 值可能会提高性能，特别是在强制运动分析中使用大质量技术时。大质量技术可能导致刚体频率与柔性频率之间产生较大的间隙。
    如果该字段为空，SHFSCL 的值将自动估算。
11：有时可能需要计算比请求更多的根，以确保找到范围内的所有根。然而，这种方法不会输出额外的根。
12：NASTRAN SYSTEM(146)（也称为 FBSMEM）提供了在 FBS 操作期间减少 I/O 的选项，具体见下表。
        SYSTEM(146)（默认值=0）说明：
        -1 或 0：在 FBS 操作期间，使用可用内存尽可能多地存储因子矩阵。在 F04 文件中打印系统信息消息 4199。
        1：禁用所有 FBS 的特殊内存操作。
        2：将稀疏方法预留的内存增加大约 200%。
        3：将稀疏方法预留的内存增加大约 300%。
        4：将稀疏方法预留的内存增加大约 400%。
13：对于分布式并行方法，V1 和 V2 之间的频率范围可以细分为多个片段，然后可以并行分析。并行方法必须指定 V1 和 V2。
    要利用并行方法，必须将 NUMS 指定为大于 1。NUMS 也可以通过 NASTRAN 语句中的 NUMSEG 关键字进行指定。
    目前，NUMSEG 必须等于处理器的数量，并且默认情况下，NUMSEG 设置为 DMP 关键字请求的处理器数量。如果两者都指定，则 NUMS 优先。
    每个片段的上限频率可以通过 ALPH 自动生成，也可以直接在 Fi 中指定。如果两者都指定，只要它们一致，则 Fi 优先于 ALPH。
    ALPH 乘以 100 也可以在 NASTRAN 语句的 FRQSEQ 关键字中指定。
14：增大 MAXSET 可能会提高处理大量特征值的大型问题的性能。默认值在所有机器上为 7。
    可以在 rcfile 文件中设置 SYSTEM(263) 来有效修改默认值；然而，EIGRL 条目中的设置始终优先。
15：SYSTEM(196)，关键字 SCRSAVE，控制当调用片段逻辑时是否重用临时文件。SYSTEM(196) 只有在 Lanczos 求解中请求多个频率片段时才有用。
    （可以通过 EIGRL 条目中的 NUMS 字段和 SYSTEM(197) 请求多个频率片段。）每个频率片段至少需要三个临时文件。
    当在单处理器计算机上使用多个频率片段时，每个片段是串行求解的。在这种情况下，允许片段 #2 使用片段 #1 已完成工作的临时文件是合理的
    （否则就无法开始片段 #2 的工作）。同样地，当片段 #2 的工作完成后，片段 #3 应该能够使用片段 #2 的临时文件。
    SYSTEM(196)=1 允许这种文件重用，并且在版本 70 及更高版本的系统上被认为是一个安全的默认设置。
16：版本 70.5 中的新屈曲移位逻辑倾向于首先移位到 1.0。如果问题要求的根数量 (ND) 较少，而 1 以下存在数千个根，
    则该逻辑可能难以找到最低的 ND 根。在这种情况下，应该对载荷进行缩放、指定 SHFSCL，或者请求更小的频率范围。
17：由于 Lanczos 方法的性能针对中到大型问题进行了优化，因此在处理非常小的问题时会遇到困难。
    因此，默认情况下，当选择 Lanczos 方法并且问题的自由度少于 20 时，方法会自动切换为 AHOU。
    自动切换的标准由 NASTRAN 条目中的 SYSTEM(359) 控制。
18：如果在 Executive Control Section 中也指定了 DOMAINSOLVER ACMS 或 DOMAINSOLVER MODES，则必须指定 V2。
19：对于屈曲问题，Lanczos 算法在首先计算最低模态，然后按量级递增计算剩余模态时最为可靠。通常，最低模态是最值得关注的模态。
    如果 V1 和 V2 字段留空，将通过一种稳健且高效的反迭代方法来估算第一个模态的特征值。如果 ND 设置为 1，
    则很有可能可靠地计算出第一个模态。如果需要更多模态，一旦确定了最低模态的位置，就更容易正确填写其他模态
20：对于屈曲问题，如果 V1 明确设置为 0.0，则将根据负移值（negative shift value）计算负特征值。这是为了避免由于移位为 0.0 导致的奇异性。
    如果 V1 设置为一个小的正值，则不会计算负特征值。此行为在 MSC Nastran 2010 版本中发生了变化，此前将 V1 设置为 0.0 时不会产生负特征值。
    不过，最好的方法是遵循 Remark 19 的建议。
21：如果存在模块，则此条目只能在主 Bulk Data 部分中指定。
*/

#pragma once

#include "DataStructure/Common/Real.h"
#include "DataStructure/Common/SGObject.h"
#include "DataStructure/Common/SetBase.h"

SG_DATASTRUCTURE_FEM_NAMESPACE_OPEN
///< @brief 使用Lanczos方法求解特征值问题（振动或者屈曲）。
struct DECLSPEC EIGRLData : public SetBase
{
    // HDF5存储中字符串数组有固定长度，其结尾没有\0,提供一个枚举值判断归一化方法
    enum MNEType : int8_t
    {
        UNKnow = 0,
        MASS   = 1,
        DISP   = 2,
    };
    SG::DataStructure::Common::Real m_v1     = 0.0;  ///< 求解下限，闭区间，见remark 2、4，(Real or blank, – 5*10^16<= V1 <= V2 <=5.*10^16 )
    SG::DataStructure::Common::Real m_v2     = 0.0;  ///< 求解上限，闭区间，见remark 2、4，(Real or blank, – 5*10^16<= V1 <= V2 <=5.*10^16 )
    SG::DataStructure::Common::I64  m_ND     = 0;    ///< 求解阶数, (Integer > 0 or blank)
    SG::DataStructure::Common::I64  m_MSGLVL = 0;    ///< 控制在特征值提取过程中诊断输出的数量，见remark 7((0 < Integer < 4; Default = 0)
    SG::DataStructure::Common::I64  m_MAXSET = 0;    ///< 在block或set中的向量个数，默认与机器相关，见remark 8
    SG::DataStructure::Common::Real m_SHFSCL = 0.0;  ///< 预估的第一阶非刚体模态，见remark 9  (Real or blank)
    SG::DataStructure::Common::I64  m_FLAG1  = -1;   ///< -1代表v1为空，非-1代表为非空
    SG::DataStructure::Common::I64  m_FLAG2  = -1;   ///< -1代表v2为空，非-1代表为非空
    char                            m_NORM[4] = { 0 };  ///< 归一化方法 (Character: “MASS” or “MAX”)
    SG::DataStructure::Common::Real m_ALPH = 0.0;  ///< 对于并行时，指定对于计算Fi时上边界段的常数(Real > 0.0; Default = 1.0):（实测H5为0）
    SG::DataStructure::Common::I64  m_domainId = 0;     ///<
    std::vector<SG::DataStructure::Common::Real> m_Fi;  ///< Fi，第i段的频率上限(Real or blank;V1<F1<F2<...<F15<V2)

    MNEType GetMNEType ()
    {
        switch (m_NORM[2])
        {
        case 'S':
            return MASS;
            break;
        case 'X':
            return DISP;
            break;
        default:
            return UNKnow;
            break;
        }
    }
};
///@{ @brief operator override

DECLSPEC bool operator== (const EIGRLData& val1, const EIGRLData& val2);
///}@

SG_DATASTRUCTURE_FEM_NAMESPACE_CLOSE